<script setup>
import * as echarts from 'echarts/core';
import {GridComponent, LegendComponent, TitleComponent, ToolboxComponent, TooltipComponent} from 'echarts/components';
import {LineChart} from 'echarts/charts';
import {UniversalTransition} from 'echarts/features';
import {CanvasRenderer} from 'echarts/renderers';
import {computed, markRaw, onBeforeUnmount, onMounted, onUnmounted, ref, toRaw, watch} from 'vue';

import {QuestionFilled, Search} from "@element-plus/icons-vue";
import requestUtil from "@/utils/request";
import {ElMessage} from "element-plus";
import store from "@/store";

echarts.use([
  TitleComponent,
  ToolboxComponent,
  TooltipComponent,
  GridComponent,
  LegendComponent,
  LineChart,
  CanvasRenderer,
  UniversalTransition
]);
echarts.registerTheme('dark', {
  backgroundColor: '#414243FF',
  textStyle: {
    color: '#fff'
  },
  title: {
    textStyle: {
      color: '#fff'
    }
  },
  legend: {
    textStyle: {
      color: '#fff'
    }
  },
  tooltip: {
    backgroundColor: '#333',
    textStyle: {
      color: '#fff'
    }
  },
})


const queryForm = ref({
  alertName: '',
  groupName: '',
  typeID: '',
  statusID: 3,
  pageNum: 1,
  pageSize: 20,
  dateTime: [],
})

const alertMsg = ref('一天内没有触发告警信息')
const showAlert = ref(true)

const monitorChartRef = ref(null);
const alertChartRef = ref(null);

const groupData = ref([])
const monStatusList = ref([])
const alertCountList = ref([])
const typeData = ref([])

const hostCount = ref(0)
const monCount = ref(0)
const alertCount = ref(0)

const datePickerVal = ref([])

const shortcuts = [
  {
    text: '最近3小时',
    value: () => {
      const end = new Date()
      const start = new Date()
      start.setHours(start.getHours() - 3)
      return [start, end]
    },
  },
  {
    text: '最近6小时',
    value: () => {
      const end = new Date()
      const start = new Date()
      start.setHours(start.getHours() - 6)
      return [start, end]
    },
  },
  {
    text: '最近12小时',
    value: () => {
      const end = new Date()
      const start = new Date()
      start.setHours(start.getHours() - 12)
      return [start, end]
    },
  },
  {
    text: '最近24小时',
    value: () => {
      const end = new Date()
      const start = new Date()
      start.setDate(start.getDate() - 1)
      return [start, end]
    },
  },
  {
    text: '最近3天',
    value: () => {
      const end = new Date()
      const start = new Date()
      start.setDate(start.getDate() - 3)
      return [start, end]
    },
  },
]

const initCountData = async () => {
  // 获取监控分组数据，和监控类型数据
  try {
    const res = await requestUtil.get('dashboard/get/num/info')
    const data = res.data
    if (data.code === 200) {
      hostCount.value = data.msg.host_count
      monCount.value = data.msg.task_count
      alertCount.value = data.msg.alert_count
    } else {
      ElMessage.error(data.msg)
    }
  } catch (error) {
    console.error('Error fetching table data:', error)
    ElMessage.error('请求失败，请稍后再试')
  }
}
initCountData()

const initGroupAndTypeData = async () => {
  // 获取监控分组数据，和监控类型数据
  try {
    const res = await requestUtil.get('monitor_alert/group/action')
    const data = res.data
    if (data.code === 200) {
      groupData.value = data.group_msg
      typeData.value = data.type_msg
    } else {
      ElMessage.error(data.msg)
    }
  } catch (error) {
    console.error('Error fetching table data:', error)
    ElMessage.error('请求失败，请稍后再试')
  }
}
initGroupAndTypeData()

const initMonStatusList = async () => {
  try {
    const res = await requestUtil.post('dashboard/get/mon/status', queryForm.value)
    const data = res.data
    if (data.code === 200) {
      monStatusList.value = data.msg
    } else {
      ElMessage.error(data.msg)
    }
  } catch (error) {
    console.error('Error fetching table data:', error)
    ElMessage.error('请求失败，请稍后再试')
  }
}

const initAlertCountList = async () => {
  try {
    const res = await requestUtil.post('dashboard/get/alert/count', queryForm.value)
    const data = res.data
    if (data.code === 200) {
      alertCountList.value = data.msg
    } else {
      ElMessage.error(data.msg)
    }
  } catch (error) {
    console.error('Error fetching table data:', error)
    ElMessage.error('请求失败，请稍后再试')
  }
}

// 在setup部分添加
const monitorChart = ref(null); // 保存图表实例
const alertChart = ref(null); // 保存图表实例

// 提取图表初始化逻辑为单独方法
const initChart = async () => {
  const processData = (rawData, id) => {
    // 转换原始响应式数据为普通JS对象，减少Proxy开销
    const data = toRaw(rawData);
    if (!data || data.length === 0) return [[], [], []];

    // 性能优化：使用Map存储时间索引
    const timeSet = new Set();
    const timeIndexMap = new Map();

    // 第一次遍历：收集所有时间并排序
    data.forEach(item => timeSet.add(item.create_time));
    const timeList = Array.from(timeSet).sort((a, b) => new Date(a) - new Date(b)); // 确保时间排序
    timeList.forEach((time, index) => timeIndexMap.set(time, index)); // O(1)查找

    // 使用对象存储系列数据，避免数组填充
    const seriesMap = {};

    // 第二次遍历：填充数据
    data.forEach(item => {
      const timeIdx = timeIndexMap.get(item.create_time);
      if (timeIdx === undefined) return;

      const seriesName = item.name__name;
      if (!seriesMap[seriesName]) {
        seriesMap[seriesName] = {
          name: seriesName,
          type: 'line',
          symbol: 'circle',
          symbolSize: 10,
          lineStyle: {width: 2},
          data: new Array(timeList.length).fill(id === 1 ? null : 0)
        };
      }

      if (id === 1) {
        seriesMap[seriesName].data[timeIdx] = item.status;
      } else {
        seriesMap[seriesName].data[timeIdx] = item.alert_count || 0;
      }
    });

    const series = Object.values(seriesMap);
    const legendData = series.map(s => s.name);

    return [timeList, series, legendData];
  };

  const monData = processData(monStatusList.value, 1);

  const timeList = monData[0]
  const series = monData[1]
  const legendData = monData[2]


  const monOption = {
    title: {
      text: '监控任务执行状态',
      subtext: '1表示检测成功，0表示检测失败',
      left: 'left'
    },
    tooltip: {
      trigger: 'axis',
      formatter: function (params) {
        let result = params[0].axisValue + '<br/>';
        params.forEach(function (item) {
          const status = item.value === 1 ? '检测成功' : '检测失败';
          result += item.marker + ' ' + item.seriesName + ': ' + status + '<br/>';
        });
        return result;
      }
    },
    legend: {
      data: legendData,
      top: 50
    },
    grid: {
      top: '45%',
      left: '3%',
      right: '4%',
      bottom: '3%',
      containLabel: true
    },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: timeList
    },
    yAxis: {
      type: 'value',
      min: 0,
      max: 1,
      interval: 1,
      axisLabel: {
        formatter: function (value) {
          return value === 1 ? '检测成功' : value === 0 ? '检测失败' : '';
        }
      }
    },
    series: series
  };

  const alertData = processData(alertCountList.value, 2);

  const dateList = alertData[0]
  const alertSeries = alertData[1]
  const alertLegendData = alertData[2]

  const alertOption = {
    title: {
      text: '告警发送量',
      left: 'left'
    },
    tooltip: {
      trigger: 'axis',
      formatter: function (params) {
        let result = params[0].axisValue + '<br/>';
        params.forEach(function (item) {
          result += item.marker + ' ' + item.seriesName + ': ' + item.value + '<br/>';
        });
        return result;
      }
    },
    legend: {
      data: alertLegendData,
      top: 50
    },
    grid: {
      top: '45%',
      left: '3%',
      right: '4%',
      bottom: '3%',
      containLabel: true
    },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: dateList
    },
    yAxis: {
      type: 'value',
    },
    series: alertSeries
  };
  alertChart.value.setOption(alertOption, true); // 注意这里的true表示不合并选项
  monitorChart.value.setOption(monOption, true); // 注意这里的true表示不合并选项
};

// 刷新数据方法
const refreshData = async () => {
  const blackStatus = computed(() => store.state.blackStatus)
  // 使用markRaw避免响应式代理，解决tooltip点击后不显示卡片的问题
  monitorChart.value = markRaw(echarts.init(monitorChartRef.value, blackStatus.value ? 'dark' : null));
  alertChart.value = markRaw(echarts.init(alertChartRef.value, blackStatus.value ? 'dark' : null));

  await initMonStatusList();
  await initAlertCountList();
  await initChart();
  console.log(Date.now(), '=============time=88888888888888==')
  if (alertCountList.value.length === 0) {
    const isEmptyDatePicker = (val) => {
      // 基础空值判断
      if (val == null) return true;

      // Proxy对象处理
      if (typeof val === 'object' && '__v_raw' in val) {
        const raw = toRaw(val);
        return Object.keys(raw).length === 0;
      }
      // 普通数组判断
      if (Array.isArray(val)) return val.length === 0;

      // 其他情况
      return !val;
    };
    if (isEmptyDatePicker(datePickerVal.value)) {
      alertMsg.value = '一天内没有触发告警信息'
    } else {
      alertMsg.value = '当前时间段没有触发告警信息'
    }
    showAlert.value = false
  } else {
    showAlert.value = true
  }
};

let timer = null;

// 修改onMounted部分
onMounted(async () => {
  // 全局覆盖ECharts事件监听，解决Added non-passive event listener to a scroll-blocking 'wheel' event警告
  const originalAddEventListener = EventTarget.prototype.addEventListener;
  EventTarget.prototype.addEventListener = function (type, listener, options) {
    if (type === 'wheel' || type === 'mousewheel') {
      options = typeof options === 'object' ?
          {...options, passive: true} :
          {passive: true};
    }
    originalAddEventListener.call(this, type, listener, options);
  };


  await refreshData();

  // 每隔60秒执行一次
  // 修改定时器逻辑，确保前一次请求完成后再发起新请求
  let isRefreshing = false;
  timer = setInterval(async () => {
    if (!isRefreshing) {
      isRefreshing = true;
      await refreshData();
      isRefreshing = false;
    }
  }, 60000);
});

onBeforeUnmount(() => {
  // 离开页面时清除定时器
  if (timer) clearInterval(timer);
  if (monitorChart.value) monitorChart.value.dispose();
  if (alertChart.value) alertChart.value.dispose();
});

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

function debounce(func, delay) {
  let timeout;
  return function () {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, arguments), delay);
  };
}

// 定义处理函数
const handleResize = debounce(() => {
  console.log('窗口尺寸稳定后触发');
  alertChart.value.dispose();
  monitorChart.value.dispose();
  refreshData();
}, 200);

// 页面加载时添加监听
onMounted(() => {
  window.addEventListener('resize', handleResize);
});
// 页面关闭前移除监听
onUnmounted(() => {
  window.removeEventListener('resize', handleResize);
});

watch(
    () => datePickerVal.value,
    () => {
      queryForm.value.dateTime = datePickerVal.value;
    }
)
watch(
    // 使用数组监听多个源
    [
      () => store.state.blackStatus,
      () => store.state.asideStatus
    ],
    async () => {
      handleResize()
    }
)

</script>

<template>
  <div class="app-container">
    <el-card style="margin-bottom: 20px">
      <div class="top-class">
        <div class="top-block border-class">
          <el-text class="font-class">主机数量：{{ hostCount }}</el-text>
        </div>
        <div class="top-block border-class">
          <el-text class="font-class">监控数量：{{ monCount }}</el-text>
        </div>
        <div class="top-block border-class">
          <el-text class="font-class">告警发送总量：{{ alertCount }}</el-text>
        </div>
      </div>
    </el-card>

    <el-card class="box-card">
      <template v-slot:header>
        <div class="space-between">
          <el-tooltip raw-content content="默认展示最近24小时的数据<br/>默认保存30天的数据" placement="right">
            <el-icon class="width-class">
              <QuestionFilled style="color: red"/>
            </el-icon>
          </el-tooltip>

          <el-text class="width-class">监控分组:</el-text>
          <el-select
              class="width-class"
              style="width: 150px"
              v-model="queryForm.groupName"
              placeholder="请选择"
              clearable
          >
            <el-option
                v-for="item in groupData"
                :key="item.id"
                :label="item.name"
                :value="item.name"
            />
          </el-select>

          <el-text class="width-class">监控类型:</el-text>
          <el-select
              class="width-class"
              style="width: 150px"
              v-model="queryForm.typeID"
              placeholder="请选择"
              clearable
          >
            <el-option
                v-for="item in typeData"
                :key="item.id"
                :label="item.name"
                :value="item.id"
            />
          </el-select>

          <el-text class="width-class">监控名称:</el-text>
          <el-input
              class="width-class"
              style="width: 150px"
              v-model="queryForm.alertName"
              placeholder="请输入监控名"
              clearable
          />
          <el-text>监控时段：</el-text>
          <el-date-picker
              v-model="datePickerVal"
              type="datetimerange"
              :shortcuts="shortcuts"
              range-separator="To"
              start-placeholder="开始时间"
              end-placeholder="截止时间"
              value-format="YYYY-MM-DD HH:mm:ss"
          />
          <el-button style="margin-left: 10px" type="primary" :icon="Search" @click="refreshData()">
            搜索
          </el-button>
        </div>
      </template>

      <div class="alert-class border-class">
        <div ref="monitorChartRef" class="alert-chart-class"></div>
      </div>

      <div class="alert-class border-class no-date-class">
        <el-text v-show="!showAlert" class="no-date-msg-class">
          {{ alertMsg }}
        </el-text>
        <div v-show="showAlert" ref="alertChartRef" class="alert-chart-class"/>
      </div>
    </el-card>
  </div>
</template>

<style scoped lang="scss">
/* 在全局或组件样式中添加 */
.echarts-tooltip {
  z-index: 9999 !important;
}

.space-between {
  //display: flex;
  //align-items: center;
  //justify-content: space-between;
  min-height: 24px;

  .width-class {
    margin-right: 10px;
  }
}

.top-class {
  display: flex;
  width: 100%;
  height: 100px;
  justify-content: space-between;

  .top-block {
    height: 100px;
    width: 500px;
    align-content: center;
    justify-content: center;
    margin-bottom: 20px;

    .font-class {
      font-weight: bold;
      font-size: 24px;
    }
  }
}

.border-class {
  display: flex;
  align-items: center;
  background-color: var(--white-color);

  border: 1px solid var(--border-color);
  //border-radius: 10px; /* 圆角效果 */
}

.no-date-class {
  display: flex;
  justify-content: center;
  align-items: center;

  .no-date-msg-class {
    font-size: 30px;
    font-weight: bold;
  }
}

.alert-class {
  height: 350px;
  margin-bottom: 20px;

  .alert-chart-class {
    width: 95%;
    height: 300px;
    margin-left: 20px
  }
}
</style>